package no.sachmuld.methodcombination.demo;

import no.sachmuld.methodcombination.api.CrosscuttingBehaviour;
import no.sachmuld.methodcombination.api.MethodCombinationSupport;
import no.sachmuld.methodcombination.api.MethodInvocation;
import no.sachmuld.methodcombination.api.annotation.Crosscutting;
import no.sachmuld.methodcombination.api.annotation.MethodCombinationException;
import no.sachmuld.methodcombination.api.annotation.UsesMethodCombination;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import javax.sql.DataSource;
import java.sql.*;
import java.util.List;

/**
 *
 */
public class EmployeeRepository extends Repository<Employee> {

    public EmployeeRepository(final DataSource dataSource) {
        with(new RepositoryBehaviour<Employee>() {

            @Override
            public Employee insert(final Employee employee, MethodInvocation<Employee> invocation) {
                final String sql = "insert into EMPLOYEE (USERNAME, SURNAME, FIRSTNAME) values (?, ?, ?)";
                KeyHolder keyHolder = new GeneratedKeyHolder();
                new JdbcTemplate(dataSource).update(new PreparedStatementCreator() {
                    @Override
                    public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                        PreparedStatement statement = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                        statement.setString(1, employee.getUsername());
                        statement.setString(2, employee.getSurname());
                        statement.setString(3, employee.getFirstname());
                        return statement;
                    }
                }, keyHolder);

                Object key = keyHolder.getKeys().get("ID");
                employee.setId((Long)key);
                return employee;
            }

            @Override
            public Employee update(Employee employee, MethodInvocation<Employee> invocation) {
                new JdbcTemplate(dataSource).update("update EMPLOYEE set USERNAME = ?, SURNAME = ?, FIRSTNAME = ? where ID = ?", employee.getUsername(), employee.getSurname(), employee.getFirstname(), employee.getId());
                return employee;
            }

            @Override
            public Employee select(Long id, MethodInvocation<Employee> invocation) {
                List<Employee> result = new JdbcTemplate(dataSource).query("select ID, USERNAME, SURNAME, FIRSTNAME from EMPLOYEE where ID = ?", new Object[] {id}, new RowMapper<Employee>() {
                    @Override
                    public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Employee employee = new Employee();
                        employee.setId(rs.getLong("ID"));
                        employee.setUsername(rs.getString("USERNAME"));
                        employee.setSurname(rs.getString("SURNAME"));
                        employee.setFirstname(rs.getString("FIRSTNAME"));
                        return employee;
                    }
                });
                if (result.size() == 0) {
                    return null;
                } else if (result.size() > 1) {
                    throw new RuntimeException("Unexpected duplicate");
                } else {
                    return result.get(0);
                }
            }

            @Override
            public List<Employee> selectAll(MethodInvocation<List<Employee>> invocation) {
                List<Employee> result = new JdbcTemplate(dataSource).query("select ID, USERNAME, SURNAME, FIRSTNAME from EMPLOYEE", new RowMapper<Employee>() {
                    @Override
                    public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
                        Employee employee = new Employee();
                        employee.setId(rs.getLong("ID"));
                        employee.setUsername(rs.getString("USERNAME"));
                        employee.setSurname(rs.getString("SURNAME"));
                        employee.setFirstname(rs.getString("FIRSTNAME"));
                        return employee;
                    }
                });
                return result;
            }

            @Override
            public void delete(Long id, MethodInvocation<Void> invocation) {
                new JdbcTemplate(dataSource).update("delete from EMPLOYEE where ID = ?", id);
            }

            @Override
            public long count(MethodInvocation<Long> invocation) {
                return new JdbcTemplate(dataSource).queryForInt("select count(*) from EMPLOYEE");
            }
        });
    }


}
